#include <ArduinoJson.h>

#include <DHTesp.h>

/*********
by Ningh 
adapted from Arduino IDE example: Examples > Arduino OTA > BasicOTA.ino 
*********/
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

#include "time.h"

#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <uri/UriBraces.h>
#include <uri/UriRegex.h>
#include <ESP8266HTTPClient.h>

#include "FS.h"
#include <LittleFS.h>

#include "smartconfig.h"
#include "airkiss.h"

#define ADC_PIN         34

StaticJsonDocument<512> doc;  




const char *hostname = "esp01s-01"; 
const char *configFilename = "/config.txt";  // <- SD library uses 8.3 filenames
const char *dhtFilename = "/dht.txt";  // <- SD library uses 8.3 filenames


ESP8266WebServer server(80);
const char* serverIndex = "<form method='POST' action='/update' enctype='multipart/form-data'><input type='file' name='update'><input type='submit' value='Update'></form>";

bool isDht = false;

// Replace with your network credentials
const char* ssid = "WZLAN";
const char* password = "5582855828";

long timezone = -8;
byte daysavetime = 0;

char buff[512];
int vref = 1100;


DHTesp dht;


String _dhtRead(){
  
  if(!isDht){   
    dht.setup(2, DHTesp::DHT11); 
    isDht = true;
  }
  
  delay(dht.getMinimumSamplingPeriod());

  float humidity = dht.getHumidity();
  float temperature = dht.getTemperature();

  Serial.print(dht.getStatusString());
  Serial.print("\t");
  Serial.print(humidity, 1);
  Serial.print("\t\t");
  Serial.print(temperature, 1);
  Serial.print("\t\t");
  Serial.print(dht.toFahrenheit(temperature), 1);
  Serial.print("\t\t");
  Serial.print(dht.computeHeatIndex(temperature, humidity, false), 1);
  Serial.print("\t\t");
  Serial.println(dht.computeHeatIndex(dht.toFahrenheit(temperature), humidity, true), 1);

  //String tt = localTime();
  
//  sprintf(buff,
//          tt+",%f,%f\n",
//          temperature,
//          humidity );

  String rets =  localTime(true) + "%2C" + String(temperature) +"%2C" + String(humidity);
  String ret =  localTime(false) + "," + String(temperature) +"," + String(humidity)+ "\n";

  showHeap();

//  appendFile(dhtFilename, ret.c_str() );
  sendDht(rets);

  showHeap();
  
  Serial.println("before return dht");

  return ret;
}

void dhtRead(){  
  String v =  _dhtRead();
  Serial.println("_dhtRead done.");
  
  server.send(200, "text/html", v );
  Serial.println("dhtRead done.");  
}

void dhtReadAll(){
  if(!isDht){
    dht.setup(2, DHTesp::DHT11); 
    isDht = true;
    dhtRead();
    return;
  }
  Serial.println("readDhtAll"); 

  String all = readFile(dhtFilename);
  
  Serial.println(all); 
 
  server.send(200, "text/html", all);
}

void setup() {

  Serial.begin(115200);
  Serial.println("Start");
  
  showHeap();
  
  Serial.print(F("\nReset reason = "));
  String resetCause = ESP.getResetReason();
  Serial.println(resetCause);

 
  loadConfiguration();

  Serial.println("Status\tHumidity (%)\tTemperature (C)\t(F)\tHeatIndex (C)\t(F)");
  String thisBoard= ARDUINO_BOARD;
  Serial.println(thisBoard);
  
//  dht.setup(2, DHTesp::DHT11); 

  WiFi.setAutoConnect(true);
 
//  WiFi.mode(WIFI_STA);
//  WiFi.begin(ssid, password);
//  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
//      _info("WZLAN FAILED");
//    delay(500);
//    ESP.restart();
//  }


  if (!autoConfig())
  {
    Serial.println("Start smartConfig module");
    smartConfig();
  }

  _info("WZLAN CONNECTED");
  _info("IP address: ");
  Serial.println(WiFi.localIP());


  Serial.printf("current hostname: %s\n", WiFi.hostname().c_str()); 
  Serial.printf("update hostname to: ");
  WiFi.hostname(hostname); 
  Serial.printf("updated hostname: %s\n", WiFi.hostname().c_str());  

  configTime(3600 * timezone, daysavetime * 3600, "0.pool.ntp.org", "1.pool.ntp.org");
  Serial.println( millis() );

  startServer();

  // Hostname defaults to esp8266-[ChipID]
  ArduinoOTA.setHostname(hostname);

  ArduinoOTA.begin();
  
  _info("ArduinoOTA READY");
  
}

void loop() {
  ArduinoOTA.handle();
  server.handleClient(); 
  // autoDht(); 
  
  // autoSleep();

  delay(2000);
  _dhtRead();

//  delay(2000);
  
//  _info("set wdtFeed");
//  ESP.wdtFeed(); // 喂狗/资源释放
  
//  _info("set WIFI disconnect");
//  WiFi.disconnect();
  
  _info("set WIFI off");
//  WiFi.mode(WIFI_OFF);

  ESP.deepSleep( 5 * 60e6); // deep sleep 5 minutes 

//  delay(5*60*1000); // hold 5 minutes
  
//  _info("going to restart ...");
  
//  ESP.restart(); // soft restart
  // ESP.reset(); // hard restart
  
  _info("set WIFI on");
  WiFi.mode(WIFI_STA);
  
  _info("set WIFI autoConfig");
  autoConfig();
  
//  _info("set WIFI reconnect");
//  WiFi.reconnect();
}

void _info( char* str){
  Serial.println(str);
}

void startServer(){
  
  server.on("/", handleRoot);
  
  server.on("/upgrade", HTTP_GET, []() {    
    _info("GET /upgrade");
    server.sendHeader("Connection", "close");
    server.send(200, "text/html", serverIndex);
  });
  
  server.on(UriBraces("/voltage/{}"), []() {
    _info("GET /voltage/{pin}");
    int pin = server.pathArg(0).toInt();
    String v = getVoltage(pin);
    server.send(200, "text/plain", v);
  });  
  
  server.on(UriBraces("/config/read/{}"), []() {
    _info("GET /config/read/{key}");

    String key = server.pathArg(0);
    loadConfiguration();
    String value = doc[key];
    
    server.send(200, "text/plain", value);
  });   // /config/read
  
  
  server.on(UriRegex("^\\/config\\/write\\/([a-zA-Z]+)\\/(.+)$"), []() {
    _info("GET /config/write/{key}/{value}");

    String key = server.pathArg(0);
    String value = server.pathArg(1);
    doc[key] = value;
    
    saveConfiguration();
    
    server.send(200, "text/plain", value);
  });   // /config/read
  
  server.on(UriRegex("^\\/fs\\/read\\/(.+)$"), []() {
    _info("GET /fs/read/{}");

    String filename = server.pathArg(0);
    
    Serial.println( filename );

    String data = readFile(filename.c_str());
    server.send(200, "text/plain", data);
    
  });  // fs/read
  
  
  server.on(UriRegex("^\\/fs\\/write\\/(.+)$"), []() {
    _info("GET /fs/write/{}");

    String filename = server.pathArg(0);
    String data = "data..";
    
    String ret = writeFile(filename.c_str(), data.c_str() );
    Serial.println( ret );
    
    server.send(200, "text/plain", ret);
  });  // /fs/write
  
  
  server.on(UriRegex("^\\/fs\\/append\\/(.+)$"), []() {
    _info("GET /fs/append/{}");

    String filename = server.pathArg(0);
    String data = "data..\n";
    
    String ret = appendFile(filename.c_str(), data.c_str() );
    Serial.println( ret );
    
    server.send(200, "text/plain", ret);
  });   // /fs/append
  
  
  server.on(UriRegex("^\\/fs\\/list\\/(.+)$"), []() {
    _info("GET /fs/list/{path}");

    String path = server.pathArg(0); 

    listDir(path.c_str());  
    
  });   // /fs/list
  
  server.on("/fs/list", []() {
    _info("GET /fs/list");

    String path = "/"; 

    listDir(path.c_str());  
    
  });   // /fs/list
  
  server.on(UriRegex("^\\/fs\\/delete\\/(.+)$"), []() {
    _info("GET /fs/delete/{}");

    String filename = server.pathArg(0); 
    
    String ret = deleteFile( filename.c_str() );
    Serial.println( ret );
    
    server.send(200, "text/plain", ret);
  });   // /fs/delete
  
  server.on("/fs/format", []() {
    _info("GET /fs/format");  
      
    if (!SPIFFS.begin()) {
      Serial.println ("SPIFFS mount failed"); 
    }
  
    SPIFFS.format();    
    
    server.send(200, "text/plain", "/fs/format done.");
  });   // /fs/delete
  
  
  
  server.on("/dht", dhtRead);  
  server.on("/dht/all",  dhtReadAll ); 
  server.on("/dht/clean",  []() {
    _info("GET /dht/clean");
    deleteFile(dhtFilename);
    server.send(200, "text/plain", "dht data cleaned!");
  });  
  
  server.on(UriRegex("^\\/dht\\/server\\/(.+)$"), []() {
    _info("GET /dht/server/{}");

    String url = server.pathArg(0);
    
    Serial.println( url );
    doc["dhtServer"] = url;
    saveConfiguration();
    
    server.send(200, "text/plain", "dht server is set to: " + url);
  });  

  server.onNotFound([]() {
    server.send(404, "text/plain", "404 Not Found!");
  });

  server.on(UriBraces("/on/{}"), []() {
    isDht = false;
    
    String p = server.pathArg(0);
    int pin = p.toInt();
    pinMode(pin, OUTPUT);
    digitalWrite(pin, HIGH);
    server.send(200, "text/plain", "set PIN on: " + p );
  });

  server.on(UriBraces("/off/{}"), []() {
    
    isDht = false;
    
    String p = server.pathArg(0);
    
    int pin = p.toInt();
    pinMode(pin, OUTPUT);
    digitalWrite(pin, LOW);
    
    server.send(200, "text/plain", "set PIN off: " + p );
  });

  

  server.on(UriBraces("/analogRead/{}"), []() {
    
    _info("GET /analogRead/{pin}");
    
    String p = server.pathArg(0);
    
    int pin = p.toInt();
    uint16_t v = analogRead(pin); 
    
    server.send(200, "text/plain", String(v) );
    
  });

  

  server.on("/update", HTTP_POST, []() {
      server.sendHeader("Connection", "close");
      server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
      ESP.restart();
    }, []() {
      HTTPUpload& upload = server.upload();
      if (upload.status == UPLOAD_FILE_START) {
        Serial.setDebugOutput(true);
        WiFiUDP::stopAll();
        Serial.printf("Update: %s\n", upload.filename.c_str());
        uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
        if (!Update.begin(maxSketchSpace)) { //start with max available size
          Update.printError(Serial);
        }
      } else if (upload.status == UPLOAD_FILE_WRITE) {
        if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
          Update.printError(Serial);
        }
      } else if (upload.status == UPLOAD_FILE_END) {
        if (Update.end(true)) { //true to set the size to the current progress
          Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
        } else {
          Update.printError(Serial);
        }
        Serial.setDebugOutput(false);
      }
      yield();
    }); // /update
  
  server.begin();
  Serial.println("HTTP server started");
   
} // start server


void handleRoot() {
  
  char temp[40096];
  int sec = millis() / 1000;
  int min = sec / 60;
  int hr = min / 60;

  snprintf(temp, 40096,

           "<html>\
  <head>\
    <meta http-equiv='refresh' content='5'/>\
    <title>ESP32 Demo</title>\
    <style>\
      body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
    </style>\
  </head>\
  <body>\
    <h1>Hello from ESP8266!</h1>\
    <p>Uptime: %02d:%02d:%02d</p>\
    <p></p>\
    <p>GET /fs/append/{path}</p>\
    <p>GET /fs/read/{path}</p>\
    <p>GET /fs/write/{path}</p>\
    <p>GET /fs/delete/{path}</p>\
    <p>GET /config/read/{key}</p>\
    <p>GET /config/write/{key}/{value}</p>\
    <p>GET /on/{pin}</p>\
    <p>GET /off/{pin}</p>\
    <p>GET /dht/</p>\
    <p>GET /dht/all</p>\
    <p>GET /dht/clean</p>\
    <p>GET /upgrade</p>\
  </body>\
</html>", 

           hr, min % 60, sec % 60
          );
  server.send(200, "text/html", temp);
  
}

void autoDht(){
    static uint64_t timeStamp = 0;
    int di = doc["dhtInterval"].as<int>();
    if (millis() - timeStamp > di ) {
        timeStamp = millis();
        _dhtRead();
    }
}

void printMillis() {
  Serial.print(F("millis() = "));  // show that millis() isn't correct across most Sleep modes
  Serial.println(millis());
  Serial.flush();  // needs a Serial.flush() else it may not print the whole message before sleeping
} 

void autoSleep(){     
    static uint64_t sleepTimeStamp = 0;
    int di = doc["sleepInterval"].as<int>();
    if (millis() - sleepTimeStamp > di ) {
      
       sleepTimeStamp = millis();
       _info("start autoSleep - deep sleep"); 

      Serial.println(F("going into Deep Sleep now..."));
      printMillis();  // show time difference across sleep 
      // ESP.deepSleep(1E6); // good night!  D0 fires a reset in 10 seconds...
      
    }
}

String getVoltage(int pin)
{   
  float volts = ESP.getVcc();
  
  Serial.printf("The internal VCC reads %1.2f volts\n", volts / 1000);
  
  String voltage = "getVoltage: " + String(  volts / 1000 );
  Serial.println(voltage);
  
//    Serial.println("getVoltage: "+ String(pin) );
//    uint16_t v = analogRead(pin | ADC_PIN);
//    float battery_voltage = ((float)v / 4095.0) * 2.0 * 3.3 * (vref / 1000.0);
//    String voltage = "Voltage :" + String(battery_voltage) + "V";
//    Serial.println(voltage);
    return voltage;     
}

void sendDht(String data){

//    if (WiFi.status() != WL_CONNECTED){
//      Serial.print("[sendDht] status not ready: " + String( WiFi.status() ) );
//      return;
//    }
//  
    HTTPClient http;
    WiFiClient client;

    Serial.print("sendDht begin...\n");
    //String url =  doc["dhtServer"].as<String>();
    // url += data;
    //String url = "http://public.zzzfree.cn/iot/dht.php?l=hc"; // "http://jigsaw.w3.org/HTTP/connection.html";
    
    String url = "http://www.baidu.com";

    String str_url = doc["dhtUrl"].as<String>();
    String str_query = doc["dhtQuery"].as<String>();  
    doGet( str_url + "?" + str_query + data );
    return;
    
    Serial.println("[URL] " + url);
    showHeap();
    
    if (http.begin(client, url)) {  // HTTP

      Serial.print("[HTTP] GET...\n");
      // start connection and send HTTP header
      int httpCode = http.GET();

      // httpCode will be negative on error
      if (httpCode > 0) {
        // HTTP header has been send and Server response header has been handled
        Serial.printf("[HTTP] GET... code: %d\n", httpCode);

        // file found at server
        if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
          Serial.println("[HTTP] GET... success");
          //String payload = http.getString();
          //Serial.println(payload);
        }
      } else {
        Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
      }
      Serial.println("before [HTTP] end");
      http.end();
      Serial.println("after [HTTP] end");
      showHeap();
    } else {
      Serial.println("[HTTP] Unable to connect\n");
    }  

    Serial.flush();
    Serial.println("[HTTP] done");
}


String writeFile(const char * path, const char * message) {
  String ret = "";
  Serial.printf("Writing file: %s\n", path);

  if (!LittleFS.begin()) {
    ret = ("LittleFS mount failed");
    return ret;
  }

  File file = LittleFS.open(path, "w+");
  if (!file) {
    ret = ("Failed to open file for writing");
    return ret;
  }
  if (file.print(message)) {
    ret = ("File written");
  } else {
    ret = ("Write failed");
  }
  delay(2000); // Make sure the CREATE and LASTWRITE times are different
  file.close();
  
  LittleFS.end();
  
  return ret;
}

String appendFile(const char * path, const char * message) {
  String ret = "";
  Serial.printf("Appending to file: %s\n", path);

  if (!LittleFS.begin()) {
    ret = ("LittleFS mount failed");
    return ret;
  }

  File file = LittleFS.open(path, "a");
  if (!file) {
    ret = ("Failed to open file for appending");
    return ret;
  }
  if (file.print(message)) {
    ret = ("Message appended");
  } else {
    ret = ("Append failed");
  }
  file.close();
  
  LittleFS.end();
  
  return ret;
}

String readFile(const char * path) {
  String ret = "";
  Serial.printf("Reading file: %s\n", path);

  if (!LittleFS.begin()) {
    ret = ("LittleFS mount failed");
    return ret;
  }

  File file = LittleFS.open(path, "r");
  if (!file) {
    ret = ("Failed to open file for reading");
    return ret;
  }

  Serial.print("Read from file: ");
  ret = file.readString();
  file.close();
  
  LittleFS.end();
  
  return ret;
}



String deleteFile(const char * path) {
  String ret = "";
  Serial.printf("Deleting file: %s\n", path);

  if (!LittleFS.begin()) {
    ret = ("LittleFS mount failed");
    return ret; 
  }

  if (LittleFS.remove(path)) {
    ret = ("File deleted");
  } else {
    ret = ("Delete failed");
  }
  LittleFS.end();
  return ret;
}

String localTime(bool escape){
  struct tm tmstruct;
    if(!getLocalTime(&tmstruct, 1000)){
    Serial.println("Failed to obtain time");
    return "";
  }
  
//  Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
    Serial.printf("\nNow is : %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct.tm_year) + 1900, (tmstruct.tm_mon) + 1, tmstruct.tm_mday, tmstruct.tm_hour, tmstruct.tm_min, tmstruct.tm_sec);
  char ret[50]; 
  //sprintf(ret, "%d-%02d-%02d %02d:%02d:%02d", (tmstruct.tm_year) + 1900, (tmstruct.tm_mon) + 1, tmstruct.tm_mday, tmstruct.tm_hour, tmstruct.tm_min, tmstruct.tm_sec);

  if(escape){
      sprintf(ret, "%d-%02d-%02d%%20%02d%%3A%02d%%3A%02d", (tmstruct.tm_year) + 1900, (tmstruct.tm_mon) + 1, tmstruct.tm_mday, tmstruct.tm_hour, tmstruct.tm_min, tmstruct.tm_sec);
  }else{
      sprintf(ret, "%d-%02d-%02d %02d:%02d:%02d", (tmstruct.tm_year) + 1900, (tmstruct.tm_mon) + 1, tmstruct.tm_mday, tmstruct.tm_hour, tmstruct.tm_min, tmstruct.tm_sec);
  }
  return ret;
  // asctime(&tmstruct);  
}



bool getLocalTime(struct tm * info, uint32_t ms) {
  uint32_t count = ms / 10;
  time_t now;

  time(&now);
  localtime_r(&now, info);

  if (info->tm_year > (2016 - 1900)) {
    return true;
  }

  while (count--) {
    delay(10);
    time(&now);
    localtime_r(&now, info);
    if (info->tm_year > (2016 - 1900)) {
      return true;
    }
  }
  return false;
}


// Loads the configuration from a file
void loadConfiguration() {   

  if (!LittleFS.begin()) {
    Serial.println ("LittleFS mount failed"); 
  }
  
  Serial.println("load Configuration ...");

  File file = LittleFS.open(configFilename, "r");
  if (!file) {
    Serial.println ("Failed to open config file for reading, using default configuration"); 
    setInitConfig();
    saveConfiguration();
    return;
  }  

  // Deserialize the JSON document
  DeserializationError error = deserializeJson(doc, file);  
  
  // Close the file (Curiously, File's destructor doesn't close the file)
  file.close();
  
  LittleFS.end();
  
  if (error){
    Serial.println(F("Failed to read file, using default configuration"));
    deleteFile(configFilename);
    setInitConfig();
    saveConfiguration();
  } 

}

void setInitConfig(){
  doc["dhtServer"]="http://public.zzzfree.cn/iot/dht.php?l=hc&v=";
  doc["dhtHost"]="public.zzzfree.cn";
  doc["dhtUrl"]="/iot/dht.php";
  doc["dhtQuery"]="l=hc&v=";
  doc["sleepInterval"] = "5000";
  doc["dhtInterval"] = "60000";  // 60s
  doc["isDhtKeepAlive"] = "1";
}


// Saves the configuration to a file
void saveConfiguration() {
  // Delete existing file, otherwise the configuration is appended to the file  

  Serial.println ("Save Configuration..."); 

  if (!LittleFS.begin()) {
    Serial.println ("LittleFS mount failed"); 
  }

 File file = LittleFS.open(configFilename, "w+");
  if (!file) {
    Serial.println("Failed to open config file for writing"); 
    return;
  }
 
  delay(2000); // Make sure the CREATE and LASTWRITE times are different   
 
  if (!file) {
    Serial.println(F("Failed to create file"));
    return;
  }

  // Serialize JSON to file
  if (serializeJson(doc, file) == 0) {
    Serial.println(F("Failed to write to Config.txt file"));
  }

  // Close the file
  file.close();

  LittleFS.end();
}
 

void listDir(const char * dirname) {
  Serial.printf("Listing directory: %s\n", dirname);  

  if (!LittleFS.begin()) {
    Serial.println ("LittleFS mount failed"); 
  }

  Dir root = LittleFS.openDir(dirname);

  String buf = "";

  while (root.next()) {
    File file = root.openFile("r");
    Serial.print("  FILE: ");
    Serial.print(root.fileName());
    Serial.print("  SIZE: ");
    Serial.print(file.size());
    time_t cr = file.getCreationTime();
    time_t lw = file.getLastWrite();

    buf += root.fileName() + ", " + String(file.size()) + "\n";    
      
    file.close();
    struct tm * tmstruct = localtime(&cr);
    Serial.printf("    CREATION: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec);
    tmstruct = localtime(&lw);
    Serial.printf("  LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec);
  }

  server.send(200, "text/plain", buf ); 
}




bool autoConfig()
{
  WiFi.begin();
  for (int i = 0; i < 20; i++)
  {
    int wstatus = WiFi.status();
    if (wstatus == WL_CONNECTED)
    {
      Serial.println("AutoConfig Success");
      Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str());
      Serial.printf("PSW:%s\r\n", WiFi.psk().c_str());
      WiFi.printDiag(Serial);
      return true;
      //break;
    }
    else
    {
      Serial.print("AutoConfig Waiting......");
      Serial.println(wstatus);
      digitalWrite(LED_BUILTIN, LOW);
      delay(500);
      digitalWrite(LED_BUILTIN, HIGH);
      delay(500);
      digitalWrite(LED_BUILTIN, LOW);
      delay(500);
      digitalWrite(LED_BUILTIN, HIGH);
      delay(500);
      digitalWrite(LED_BUILTIN, LOW);
      delay(500);
      digitalWrite(LED_BUILTIN, HIGH);
      delay(1000);
    }
  }
  Serial.println("AutoConfig Faild!" );
  return false;
  //WiFi.printDiag(Serial);
}
void smartConfig()
{
  WiFi.mode(WIFI_STA);
  Serial.println("\r\nWait for Smartconfig");
  
  WiFi.setAutoConnect(true);  // 设置自动连接
  WiFi.beginSmartConfig();
  while (1)
  {
    Serial.print(".");
    
    digitalWrite(LED_BUILTIN, LOW);
    delay(500);
    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);
    digitalWrite(LED_BUILTIN, LOW);
    delay(500);
    digitalWrite(LED_BUILTIN, HIGH);
    delay(1000);
      
    if (WiFi.smartConfigDone())
    {
      Serial.println("SmartConfig Success");
      Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str());
      Serial.printf("PSW:%s\r\n", WiFi.psk().c_str());
      WiFi.setAutoConnect(true);  // 设置自动连接
      break;
    }
    delay(1000); // 这个地方一定要加延时，否则极易崩溃重启
  }
}

void showHeap(){
  long  fh = ESP.getFreeHeap();
  char  fhc[20];

  ltoa(fh, fhc, 10);
  String freeHeap = String(fhc);
  Serial.println("freeHeap: " + freeHeap);
}

void doGet(String url){

  Serial.println("start doGet..");
  //url = "/";
  
  WiFiClient client;

  String str_host = doc["dhtHost"].as<String>();
  
  const char*  host = str_host.c_str(); //   "public.zzzfree.cn";
  const int  httpsPort = 80;

  /**
   * 测试是否正常连接
   */
  if (!client.connect(host, httpsPort)) {
    Serial.println("connection failed");
    return;
  }
  delay(10);

  String postRequest =(String)("GET ") + url + " HTTP/1.1\r\n" +
    "Content-Type: text/html;charset=utf-8\r\n" +
    "Host: " + host + "\r\n" +
    "User-Agent: BuildFailureDetectorESP8266\r\n" +
    "Connection: Keep Alive\r\n\r\n";
  Serial.println(postRequest);
  client.print(postRequest);  // 发送HTTP请求

  /**
   * 展示返回的所有信息
   */
  Serial.println("Response >>>>>>>>>>>>>>>>>>>>>>"); 
  String line = client.readStringUntil('\n');
  int i = 0;
  while(line.length() != 0 && i++ < 7 ){
    Serial.println(line);
    line = client.readStringUntil('\n');
  }
  Serial.println(line);
  client.stop();
  delay(3000);

  
}
 